package Lambda.DefaultMeAndStaticMe;

import java.util.function.Supplier;

/**
 * Created by LeeXyan on 2017/03/24.
 * 接口的默认方法与静态方法
 * Java 8用默认方法与静态方法这两个新概念来扩展接口的声明。
 * 默认方法使接口有点像Traits（Scala中特征(trait)类似于Java中的Interface，
 * 但它可以包含实现代码，也就是目前Java8新增的功能），但与传统的接口又有些不一样，
 * 它允许在已有的接口中添加新方法，而同时又保持了与旧版本代码的兼容性。
 */
public class DefaultMeAndStaticMe {


    /**
     * 默认方法与抽象方法不同之处在于抽象方法必须要求实现，但是默认方法则没有这个要求。
     * 相反，每个接口都必须提供一个所谓的默认实现，
     * 这样所有的接口实现者将会默认继承它（如果有必要的话，可以覆盖这个默认实现）。让我们看看下面的例子：
     */
    private interface Defaulable {
        // Interfaces now allow default methods, the implementer may or
        // may not implement (override) them.
        default String notRequired() {
            return "Default implementation";
        }
    }
    private static class DefaultableImpl implements Defaulable {
    }

    private static class OverridableImpl implements Defaulable {
        @Override
        public String notRequired() {
            return "Overridden implementation";
        }
    }
    /**
     * Defaulable接口用关键字default声明了一个默认方法notRequired()，
     * Defaulable接口的实现者之一DefaultableImpl实现了这个接口，并且让默认方法保持原样。
     * Defaulable接口的另一个实现者OverridableImpl用自己的方法覆盖了默认方法。
     */


    /**
     * Java 8带来的另一个有趣的特性是接口可以声明（并且可以提供实现）静态方法。例如：
     */
    private interface DefaulableFactory {
        // Interfaces now allow static methods
        static Defaulable create( Supplier< Defaulable > supplier ) {
            return supplier.get();
        }
    }


    /**
     * 下面的一小段代码片段把上面的默认方法与静态方法黏合到一起。
     */
    public static void main(String[] args) {
        Defaulable defaulable = DefaulableFactory.create( DefaultableImpl::new );
        System.out.println( defaulable.notRequired() );

        defaulable = DefaulableFactory.create( OverridableImpl::new );
        System.out.println( defaulable.notRequired() );
    }

    /**
     * 在JVM中，默认方法的实现是非常高效的，并且通过字节码指令为方法调用提供了支持。
     * 默认方法允许继续使用现有的Java接口，而同时能够保障正常的编译过程。
     * 这方面好的例子是大量的方法被添加到java.util.Collection接口中去：stream()，parallelStream()，forEach()，removeIf()，……
     *
     *
     *  尽管默认方法非常强大，但是在使用默认方法时我们需要小心注意一个地方：
     *  在声明一个默认方法前，请仔细思考是不是真的有必要使用默认方法，
     *  因为默认方法会带给程序歧义，并且在复杂的继承体系中容易产生编译错误。更多详情请参考官方文档
     */

}
